package org.six11.olive3.picturephone;

import static org.six11.util2.layout.FrontEnd.*;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.*;

import org.six11.olive3.client.OliveDrawingSurface;
import org.six11.olive3.client.OliveState;
import org.six11.olive3.net.Message;
import org.six11.olive3.net.MessageNames;
import org.six11.olive3.net.OliveNetworkTransmitter;
import org.six11.olive3.picturephone.server.PPMessageNames;
import org.six11.olive3.util.MultiState;
import org.six11.util2.Debug;
import org.six11.util2.layout.FrontEnd;

/**
 * 
 * 
 * @author Gabe Johnson <johnsogg@cmu.edu>
 */
public class PicturephoneRatePane extends JPanel {

  private OliveDrawingSurface oliveA, oliveB;
  private OliveNetworkTransmitter xmit;
  private MultiState programState;
  private ButtonGroup likertGroup;
  private JButton noButton;
  private String[] toolTips;

  private static String INSTRUCT_LABEL = "instruction label";
  private static String DRAW_A = "draw a";
  private static String DRAW_B = "draw b";
  private static String BAD = "bad";
  private static String GOOD = "good";
  private static String SCALE = "scale";
  private static String CONTROLS = "controls";
  
  // These two constants are keys into the programState for the sketch IDs for surfaces A and B
  private static String K_A = PPMessageNames.PARAM_SURFACE_TARGET + " "
      + PPMessageNames.PARAM_SKETCH_ID_A;
  private static String K_B = PPMessageNames.PARAM_SURFACE_TARGET + " "
      + PPMessageNames.PARAM_SKETCH_ID_B;

  private OliveState oliveStateA, oliveStateB;
  private PicturephoneControlBox controlBox;
  
  public PicturephoneRatePane(OliveNetworkTransmitter xmit, final MultiState programState) {
    this.xmit = xmit;
    this.programState = programState;
    this.controlBox = new PicturephoneControlBox(null, null, programState);
    this.toolTips = new String[] {
        "Objects unrelated",
        "Objects in same category",
        "Objects of same kind within category",
        "Object of same kind with same main features",
        "Objects of same kind with same minor features"
    };
    ActionListener al = new ActionListener() {
      public void actionPerformed(ActionEvent ev) {
        int rating = Integer.parseInt(ev.getActionCommand());
        uploadRating(rating);
      }
    };

    FrontEnd fe = new FrontEnd();
    int dim = 380;
    oliveStateA = new OliveState(programState);
    oliveA = new OliveDrawingSurface(xmit, oliveStateA);
    oliveA.setPenEnabled(false);
    oliveA.setPreferredSize(new Dimension(dim, dim));
    oliveA.setXScale((double) dim / (double) 400);
    oliveA.setYScale((double) dim / (double) 400);
    oliveStateB = new OliveState(programState);
    oliveB = new OliveDrawingSurface(xmit, oliveStateB);
    oliveB.setPenEnabled(false);
    oliveB.setPreferredSize(new Dimension(dim, dim));
    oliveB.setXScale((double) dim / (double) 400);
    oliveB.setYScale((double) dim / (double) 400);

    JLabel instructLabel = new JLabel("How similar are these two drawings?");
    instructLabel.setFont(new Font("Dialog", Font.PLAIN, 24));
    instructLabel.setHorizontalAlignment(SwingConstants.CENTER);

    JLabel badLabel = new JLabel("Not similar at all");
    JLabel goodLabel = new JLabel("Almost exactly the same");

    likertGroup = new ButtonGroup();
    JPanel likertPanel = new JPanel(new GridLayout(1, 0));
    for (int i = 1; i < 6; i++) {
      JRadioButton b = makeOption(i, al);
      likertGroup.add(b);
      likertPanel.add(b);
    }
    noButton = new JButton("none");
    likertGroup.add(noButton);

    int V_GAP = 20;
    int H_GAP = 20;
    fe.add(controlBox, CONTROLS);
    fe.add(instructLabel, INSTRUCT_LABEL);
    fe.add(oliveA, DRAW_A);
    fe.add(oliveB, DRAW_B);
    fe.add(badLabel, BAD);
    fe.add(goodLabel, GOOD);
    fe.add(likertPanel, SCALE);

    fe.addRule(ROOT, N, CONTROLS, N);
    fe.addRule(ROOT, E, CONTROLS, E);
    
    fe.addRule(CONTROLS, S, INSTRUCT_LABEL, N, V_GAP);
    fe.addRule(ROOT, W, INSTRUCT_LABEL, W);
    fe.addRule(ROOT, E, INSTRUCT_LABEL, E);

    fe.addRule(ROOT, W, DRAW_A, W);
    fe.addRule(INSTRUCT_LABEL, S, DRAW_A, N, V_GAP / 2);
    fe.addRule(ROOT, E, DRAW_B, E);
    fe.addRule(INSTRUCT_LABEL, S, DRAW_B, N, V_GAP / 2);

    fe.addRule(ROOT, W, BAD, W, H_GAP);
    fe.addRule(ROOT, S, BAD, S, V_GAP);
    fe.addRule(ROOT, E, GOOD, E, H_GAP);
    fe.addRule(ROOT, S, GOOD, S, V_GAP);

    fe.addRule(ROOT, S, SCALE, S, V_GAP);
    fe.addRule(BAD, E, SCALE, W, 30);
    fe.addRule(GOOD, W, SCALE, E);

    setLayout(new BorderLayout());
    add(fe, BorderLayout.CENTER);

    xmit.getStreamHandler().registerAsynchronousHandler(PPMessageNames.MSG_RATE_RES,
        new AWTMessageHandler() {
          public void awtHandleLater(Message m) {
            String which = m.getParamValue(PPMessageNames.PARAM_SURFACE_TARGET);
            OliveDrawingSurface surf = which.equals("a") ? oliveA : oliveB;
            String key = which.equals("a") ? K_A : K_B;
            programState.setValue(key, m.getParamValue(PPMessageNames.PARAM_SKETCH_ID));
            surf.getForeignPenHandler().handleLater(m);
            bug("* Rating sketches " + programState.getValue(K_A) + " and "
                + programState.getValue(K_B));
          }
        });
  }

  protected void uploadRating(int rating) {
    Message rateMessage = new Message(PPMessageNames.MSG_RATE_DONE);
    rateMessage.addParam(MessageNames.PARAM_USER_ID, programState
        .getString(MessageNames.PARAM_USER_ID));
    String sketchA = programState.getString(K_A);
    String sketchB = programState.getString(K_B);
    rateMessage.addParam(PPMessageNames.PARAM_SKETCH_ID_A, sketchA);
    rateMessage.addParam(PPMessageNames.PARAM_SKETCH_ID_B, sketchB);
    rateMessage.addParam(PPMessageNames.PARAM_RATE_VALUE, "" + rating);
    xmit.addBodilessMessage(rateMessage);
    resetTemporaryState();
    bug("-> Rated sketch " + sketchA + " with grandparent sketch " + sketchB + " rating of "
        + rating);
  }

  private void bug(String what) {
    Debug.out("PicturephoneRatePane", what);
  }

  protected void resetTemporaryState() {
    oliveStateA.clearSurface();
    oliveStateB.clearSurface();
    programState.setValue(K_A, null);
    programState.setValue(K_B, null);
    likertGroup.setSelected(noButton.getModel(), true);
    programState.whackValue(PicturephoneUI.DONE);
  }

  private JRadioButton makeOption(int i, ActionListener al) {
    JRadioButton b = new JRadioButton();
    b.setActionCommand(i + "");
    b.addActionListener(al);
    b.setToolTipText(toolTips[i-1]);
    bug("Set tooltip text for button to " + toolTips[i-1]);
    return b;
  }

}
